﻿using System;
using System.Collections.Generic;
using System.Text;
using Tsanie.DmPoster.Models;

namespace Tsanie.DmPoster.Utils {
    public delegate bool Exec<T>(T t1, T t2);

    internal class SortedLinkedList {
        private class Node {
            public UsedPos Value;
            public Node Next;
            public Node Prev;
            public Node(UsedPos value) : this(null, null, value) { }
            public Node(Node next, Node prev, UsedPos value) {
                this.Next = next;
                this.Prev = prev;
                this.Value = value;
            }
        }

        private int _count;
        private Node _first, _last;
        public int Count { get { return _count; } }
        public UsedPos First { get { return (_first == null ? null : _first.Value); } }
        public UsedPos Last { get { return (_last == null ? null : _last.Value); } }

        public SortedLinkedList() {
            _first = null;
            _last = null;
            _count = 0;
        }
        public void Add(UsedPos value) {
            if (Exist(value.Comment))
                return;

            Node add = new Node(value);
            _count++;
            if (_first == null) {
                _first = _last = add;
                return;
            }
            Node node = _first;
            while (node != null) {
                if (node.Value.Top > value.Top) {
                    // 插到前面
                    Node prev = node.Prev;
                    node.Prev = add;
                    add.Next = node;
                    add.Prev = prev;
                    if (prev != null) {
                        prev.Next = add;
                    } else {
                        // 头
                        _first = add;
                    }
                    return;
                }
                node = node.Next;
            }
            // 尾
            _last.Next = add;
            add.Prev = _last;
            _last = add;
        }
        public void Removes(double current) {
            Node node = _first;
            while (node != null) {
                if (node.Value.JoinTime + node.Value.Duration < current) {
                    Remove(node);
                }
                node = node.Next;
            }
        }
        public void RemoveScrolls(double current) {
            Node node = _first;
            while (node != null) {
                if ((node.Value.Comment.X + node.Value.Width < 466)
                    || node.Value.JoinTime + node.Value.Duration < current) {
                    Remove(node);
                }
                node = node.Next;
            }
        }
        public void RemoveNScrolls(double current) {
            Node node = _first;
            while (node != null) {
                if ((node.Value.Comment.X > 542)
                    || node.Value.JoinTime + node.Value.Duration < current) {
                    Remove(node);
                }
                node = node.Next;
            }
        }
        private void Remove(Node node) {
            if (node == _first) {
                // 删头
                _first = node.Next;
                if (_first == null)
                    _last = _first;
                else
                    _first.Prev = null;
            } else if (node == _last) {
                // 删尾
                _last = node.Prev;
                if (_last == null)
                    _first = _last;
                else
                    _last.Next = null;
            } else {
                // 删中间
                node.Prev.Next = node.Next;
                node.Next.Prev = node.Prev;
            }
            _count--;
        }
        public void Foreach(Exec<UsedPos> exec) {
            Node node = _first;
            while (node != null && node != _last) {
                if (exec(node.Value, node.Next.Value))
                    break;
                node = node.Next;
            }
        }
        public void ForeachBack(Exec<UsedPos> exec) {
            Node node = _last;
            while (node != null && node != _first) {
                if (exec(node.Value, node.Prev.Value))
                    break;
                node = node.Prev;
            }
        }
        public bool Exist(BiliComment comm) {
            Node node = _first;
            bool exist = false;
            while (node != null) {
                if (node.Value.Comment == comm) {
                    exist = true;
                    break;
                }
                node = node.Next;
            }
            return exist;
        }
        public override string ToString() {
            StringBuilder sb = new StringBuilder();
            sb.Append("[");
            Node node = _first;
            while (node != null) {
                sb.Append(node.Value.Top + ", ");
                node = node.Next;
            }
            if (sb.Length > 1)
                sb.Length -= 2;
            sb.Append("]");
            return sb.ToString();
        }
    }

    internal class UsedPos {
        public int Width;
        public int Top;
        public int Bottom;
        public double Duration;
        public double JoinTime;
        public int Type;
        public BiliComment Comment;

        public UsedPos(int width, int top, int bottom, double duration,
            double joinTime, int type, BiliComment comm) {
            this.Width = width;
            this.Top = top;
            this.Bottom = bottom;
            this.Duration = duration;
            this.JoinTime = joinTime;
            this.Type = type;
            this.Comment = comm;
        }
        public override string ToString() {
            return Top.ToString();
        }
    }
}
